package com.hornsun.jwt;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.joda.time.DateTime;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;

/**
 * Factory class that should be always used to create {@link JwtToken}.
 *
 * @author 编译中、、
 * @date 2017/12/24
 */
@Component
public class JwtTokenFactory {

    @Resource
    private JwtProperties jwtProperties;

    public void parseJwtToken(String token) {

    }

    public AccessJwtToken createAccessJwtToken(UserDetails userDetails) {
        if (!(userDetails instanceof AuthorizedClient)) {
            throw new IllegalStateException("Cannot create JWT Token because not authorized");
        }

        AuthorizedClient authorizedClient = (AuthorizedClient) userDetails;
        if (StringUtils.isEmpty(authorizedClient.getUsername())) {
            throw new IllegalArgumentException("Cannot create JWT Token without username");
        }

        if (authorizedClient.getAuthorities() == null || authorizedClient.getAuthorities().isEmpty()) {
            throw new IllegalArgumentException("User doesn't have any privileges");
        }
        Claims claims = Jwts.claims().setSubject(authorizedClient.getUsername());
        claims.put("authorities", authorizedClient.getAuthorities().stream().map(GrantedAuthority::getAuthority).toArray());
        claims.put("id", authorizedClient.getId());
        claims.put("password", AuthorizedClient.CREDENTIAL_WITH_JWT_TOEKN);

        DateTime currentTime = new DateTime();
        String token = Jwts.builder()
                .setClaims(claims)
                .setIssuer("CabinetGuru")
                .setIssuedAt(currentTime.toDate())
                .setExpiration(currentTime.plusMinutes(jwtProperties.getExpireTime()).toDate())
                .signWith(SignatureAlgorithm.HS512, jwtProperties.getSigningKey())
                .compact();

        return new AccessJwtToken(token, claims);
    }


    public AccessJwtToken renewAccessJwtToken(String tokenPayload) {
        if (StringUtils.isEmpty(tokenPayload)) {
            throw new IllegalArgumentException("Cannot create JWT Token without tokenPayload");
        }

        RawAccessJwtToken rawAccessToken = new RawAccessJwtToken(tokenPayload);

        Claims claims = rawAccessToken.parseClaims(jwtProperties.getSigningKey()).getBody();
        DateTime currentTime = new DateTime();
        String token = Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(currentTime.toDate())
                .setExpiration(currentTime.plusMinutes(jwtProperties.getExpireTime()).toDate())
                .signWith(SignatureAlgorithm.HS512, jwtProperties.getSigningKey())
                .compact();

        return new AccessJwtToken(token, claims);
    }
}
